/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Peer;

import FileStructure.BitField;
import java.io.*;
import java.util.logging.*;
import model.PeerEntity;
import FileStructure.FileHandler;
import Peer.peerRequest.*;
import java.util.ArrayList;

/**
 *
 * @author user
 */
public class PeerSender implements Runnable{
    PeerEntity peer;
    PeerEntity listener;
    public String dir;


    public PeerSender(PeerEntity pe, PeerEntity listener){
        this.peer = pe;
        this.listener = listener;
    }

    public void sendMessage(String msg){
        try {

            PrintWriter out = new PrintWriter(peer.peerSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(peer.peerSocket.getInputStream()));
            out.println(msg);
//            out.close();
//            in.close();
//            this.server.close();

        } catch (IOException ex) {
            Logger.getLogger(PeerSender.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void sendByteArray(byte[] bytes){
        try {

            OutputStream socketOutputStream = peer.peerSocket.getOutputStream();
            socketOutputStream.write(bytes);

        } catch (IOException ex) {
            Logger.getLogger(PeerSender.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void receiveMessage(){
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(peer.peerSocket.getInputStream()));
//            if ((this.peer.message = in.readLine()) != null) {
//                System.out.println(this.peer.message);
//            }
            System.out.println("read byte = "+ in.read());
            System.out.println("read byte = "+ in.read());
            System.out.println("read byte = "+ in.read());
            System.out.println("read byte = "+ in.read());
        } catch (IOException ex) {
            Logger.getLogger(PeerSender.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void readResponseFile(){
        try {
            FileHandler fh = new FileHandler();
            fh.readResponseFile(dir);
            this.peer.resp.failure_reason = fh.failure_reason_value;
            this.peer.resp.complete = Integer.parseInt(fh.complete_value);
            this.peer.resp.incomplete = Integer.parseInt(fh.incomplete_value);
            this.peer.resp.warning_message = fh.warning_reason_value;
            this.peer.resp.interval = Integer.parseInt(fh.interval_value);
            //peer
            for(int i=0; i<fh.ip_peer.size(); i++){
                this.peer.resp.addPeer(fh.ip_peer.get(i), Integer.parseInt(fh.port_peer.get(i)));
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(PeerDownloads.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void handshake(){
        //baca dari response file
        this.peer.handshake = new handShakeType(this.peer.request.file_name);
        String msg = this.peer.handshake.pstrlen + this.peer.handshake.pstr + "00000000" + this.peer.handshake.info_hash;
        this.peer.message = msg;
        this.sendMessage(this.peer.message);
    }

    public void sendBitField(String dir, String output_file, String torrentFilename){
        try {
            //si peer udah punya file torrentnya
            //output file mungkin belum lengkap
            //dapetin bitfield dari file
            //yg ngirim ini si listener
            BitField bitf = new BitField(dir, output_file, torrentFilename);
            
            bitf.generateBoolField();

            bitField bf = new bitField(bitf.byteField);
            //simpan bit field
            System.out.println("id = " +bf.id);
            //gabung jadi array of byte
            KoTorrentInt k = new KoTorrentInt(bf.len.bytes);
            byte[] apbb = k.appendByteBytes(bf.id, bf.bitF);
            peer.byteField = bf.bitF;

            byte[] ap = k.appendBytes(k.bytes, apbb);
            
            this.sendByteArray(ap);
            //System.out.println(KoTorrentInt.displayBytes(ap));

        } catch (IOException ex) {
            Logger.getLogger(PeerListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendRequest(){
        //yg ngirim ini si peer
        //listener baca bitfield
        //representasikan sbg piece index, terus kirim request

        ArrayList<Integer> forRequest = new ArrayList<Integer>();
        int start = 0;
        int end = 8;
        for(int j=0; j<peer.byteField.length; j++){
            for(int i=start; i<end; i++){
                boolean t = BitField.getBit(peer.byteField, i);
                if (t){
                    forRequest.add(i);
                }
                
            }
            start += 8;
            end += 8;
        }

        //pilih piece pertama
        int pi = peer.currPieceIdx;
        blockRequest br = new blockRequest(forRequest.get(listener.currPieceIdx),0,64); //1 piece = 1 block
        //cari next idx
        System.out.println("current piece idx request = " + listener.currPieceIdx);
        pi++;
        peer.currPieceIdx = pi;
        //append byte
        byte[] msg = KoTorrentInt.appendBytesByte(br.len.bytes, br.id);
        byte[] msg2 = KoTorrentInt.appendBytes
                        (KoTorrentInt.appendBytes(KoTorrentInt.appendBytes(msg, br.index.bytes),br.begin.bytes),br.length.bytes);
//        for(int i=0; i<msg2.length; i++){
//            System.out.print("m req = "+msg2[i]);
//        }
        //simpen info request ke listener
        listener.blockrequest = br;
        this.sendByteArray(msg2);
        System.out.print("message request = ");
        for(int i=0; i<msg2.length; i++){
            System.out.print(msg2[i]);
        }
        System.out.println("");
    }

    public void sendPiece(){
        try {
            System.out.println("sending piece...");
            //        try {
            //giliran si listener ngirim piece
            //baca dulu dari blockrequest
            //bytenya dapet dari file asli yg udah displit buffernya
            //            byte[][] sbf = listener.createSplitBuffer("test/", "laguku.mp3");
            //            for(int i=0; i<sbf.length; i++){
            //                System.out.println("split buffer : ");
            //                System.out.println(sbf[i][i]);
            //            }
            ArrayList<Byte> payload = new ArrayList<Byte>();
            FileHandler fh = new FileHandler();
            byte[] pl = FileHandler.generatePayLoad(dir, this.listener.request.file_name, listener.blockrequest.index.getInt());
            for(int i=0; i<pl.length; i++){
                payload.add(pl[i]);
            }
            
            piece p = new piece(listener.blockrequest.index, listener.blockrequest.begin, payload);
            //        } catch (IOException ex) {
            //            Logger.getLogger(PeerSender.class.getName()).log(Level.SEVERE, null, ex);
            //        }
            //append semua byte
            byte[] msg = KoTorrentInt.appendBytesByte(p.len.getBytes(),p.id);
            byte[] msg2 = KoTorrentInt.appendBytes(
                            KoTorrentInt.appendBytes(KoTorrentInt.appendBytes(msg, p.index.getBytes()),
                                                    p.begin.getBytes()),
                                                   pl
                                                    );
            listener.piece = p;
            System.out.print("message piece = ");
            for(int i=0; i<msg2.length; i++){
                System.out.print(msg2[i]);
            }
            System.out.println("");
            this.sendByteArray(msg2);
        } catch (IOException ex) {
            Logger.getLogger(PeerSender.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }

    public void sendCancel(){
        
    }

    public void run() {
        try {
            //throw new UnsupportedOperationException("Not supported yet.");

            this.peer.resp.addPeer("127.0.0.1", 1234);
            //thread 1 buat listener
            //thread 2 buat sender
            
                this.peer.createSenderSocket("127.0.0.1", this.peer.resp.peers.get(0).Port);
                //this.peer.request.file_name = "laguku.mp3";
             while(true){
                 this.handshake();
                Thread.sleep(1000);

                System.out.println("Sender file name = " + this.listener.request.file_name);
                this.sendBitField(dir, this.listener.request.file_name, this.listener.request.file_name + ".torrent");
                Thread.sleep(1000);
                this.sendRequest();
                Thread.sleep(1000);
                this.sendPiece();
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(PeerSender.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


    public static void main(String[] args){
        //PeerSender ps = new PeerSender(new PeerEntity("127.0.0.1",1235,true));
        //ps.peer.createSenderSocket("127.0.0.1", 1234);

        //ps.handshake();

//        ps.peer.createListener();
//        ps.receiveMessage();
    }
}

